package org.gnu.williamjoy.marycircles.view;

import java.util.Random;
import java.util.Vector;

import org.gnu.williamjoy.marycircles.R;
import org.gnu.williamjoy.marycircles.control.GameState;
import org.gnu.williamjoy.marycircles.model.Circle;
import org.gnu.williamjoy.marycircles.model.CirclesRoom;
import org.gnu.williamjoy.marycircles.model.MovingCircle;
import org.gnu.williamjoy.marycircles.model.TrackPoint;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.RadialGradient;
import android.graphics.RectF;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;

public class CirclesDrawView extends View implements OnTouchListener {
    private static final int head_status_line = 10;
    private int PRESS_QUEUE_LENGTH = this.getResources().getInteger(
            R.integer.max_press_queue_len);

    private Vector<TrackPoint> track = new Vector<TrackPoint>();
    private Circle currentCircle = new Circle(0, 0, 0, 0);

    Paint paint = new Paint();
    private static Random RANDOM_GEN = new Random();
    private boolean show_tip = true;
    private boolean draw_track = false;
    private float speedUpRatio = this.getResources().getInteger(
            R.integer.moving_speed_up_ratio);
    Bitmap bitmap_mary;
    Bitmap bitmap_william;
    private RectF rectF = new RectF();
    private MovingCircle mary;
    private MovingCircle william;

    public RectF getRectF() {
        return rectF;
    }

    public void init() {
        room = new CirclesRoom(this, game);
        bitmap_mary = BitmapFactory.decodeResource(getResources(),
                R.drawable.ic_m);
        bitmap_william = BitmapFactory.decodeResource(getResources(),
                R.drawable.ic_w);
        mary = new MovingCircle(RANDOM_GEN.nextInt(400) + 40,
                RANDOM_GEN.nextInt(600) + 40, 36, randomColor() | Color.BLACK);
        this.room.add(mary);
        mary.setDx(RANDOM_GEN.nextInt(20) - 10);
        mary.setDy(RANDOM_GEN.nextInt(20) - 10);
        william = new MovingCircle(RANDOM_GEN.nextInt(400) + 40,
                RANDOM_GEN.nextInt(600) + 40, 36, randomColor() | Color.BLACK);

        william.setDx(RANDOM_GEN.nextInt(20) - 10);
        william.setDy(RANDOM_GEN.nextInt(20) - 10);
        this.room.add(william);
        game.start();
    }

    /*
     * Try using Lock
     */
    private CirclesRoom room;

    private GameState game;

    public CirclesDrawView(Context context) {
        super(context);
        setFocusable(true);
        setFocusableInTouchMode(true);
        this.setOnTouchListener(this);
        paint.setColor(Color.WHITE);
        paint.setAntiAlias(true);
    }

    @Override
    public void onDraw(Canvas canvas) {
        this.setBackgroundColor(game.getLevelColor());
        if (this.draw_track) {
            paint.setColor(currentCircle.color);
            canvas.drawCircle(currentCircle.x, currentCircle.y,
                    currentCircle.radius, paint);
        }
        paint.setDither(true);
        for (MovingCircle c : room.getCircles()) {
            paint.setColor(c.color);
            RadialGradient gradient = new RadialGradient(c.x, c.y, c.radius,
                    Color.WHITE, c.color | Color.BLACK,
                    android.graphics.Shader.TileMode.CLAMP);
            paint.setShader(gradient);
            canvas.drawCircle(c.x, c.y, c.radius, paint);
            paint.setShader(null);
            paint.setColor((0xffffffff - c.color) | Color.BLACK);
            canvas.drawText("+" + c.getCollision(), c.x - 10, c.y + 4, paint);
        }
        canvas.drawBitmap(bitmap_mary, mary.x+1 - mary.radius, mary.y+1
                - mary.radius, paint);
        canvas.drawBitmap(bitmap_william, william.x +1 - william.radius, william.y + 1 
                - william.radius, paint);
        if (show_tip) {
            canvas.drawText("Slide to create circles", 200, rectF.bottom / 2,
                    paint);
        } else if (!room.isRunning()) {
            canvas.drawText("Paused", 200, 50, paint);
        }

        drawStatus(canvas);
        paint.setColor((0xffffffff - game.getLevelColor()) | Color.BLACK);
        canvas.drawText(
                "Level:" + game.getLevel() + " Mary(" + mary.getCollision()
                        + "),William(" + william.getCollision() + ")",
                rectF.right - 180, head_status_line, paint);
    }

    public void drawStatus(Canvas canvas) {
        float condition = game.getMaxCircles() + 1;
        float length = rectF.right / 4.0f;
        int count = room.getCircles().length;
        float ratio = count / condition;
        LinearGradient lg = new LinearGradient(0, 0, rectF.right / 2,
                head_status_line, new int[] { Color.RED, Color.YELLOW,
                        Color.GREEN, Color.YELLOW, Color.RED }, new float[] {
                        0, 0.45f, 0.56f, 0.7f, 1 },
                android.graphics.Shader.TileMode.CLAMP);
        paint.setShader(lg);
        if (count < condition)
            canvas.drawRect(0, 0, length * ratio, head_status_line, paint);
        else
            canvas.drawRect(0, 0, length + 25 * (count - condition + 1),
                    head_status_line, paint);
        paint.setShader(null);
        if (count == condition || count == condition + 1) {
            paint.setColor(Color.GREEN);
            canvas.drawRect(0, 0, head_status_line, head_status_line, paint);
        }
    }

    public boolean onTouch(View view, MotionEvent e) {
        int action = e.getAction();

        switch (action) {
        case MotionEvent.ACTION_DOWN:
            this.onTouchDown(view, e);
            break;
        case MotionEvent.ACTION_MOVE:
            this.onTouchMove(view, e);
            break;
        case MotionEvent.ACTION_UP:
            this.onTouchUp(view, e);
            break;
        default:
            break;
        }
        return true;
    }

    private void onTouchUp(View view, MotionEvent e) {
        if (!room.isRunning()) {
            this.room.setRunning(true);
            this.draw_track = false;
            return;
        }
        MovingCircle m = new MovingCircle(e.getX(), e.getY(),
                currentCircle.radius, currentCircle.color);

        this.draw_track = false;

        float dx = track.lastElement().getX() - track.firstElement().getX();
        float dy = track.lastElement().getY() - track.firstElement().getY();
        long time = track.lastElement().getTimestamp()
                - track.firstElement().getTimestamp();

        if (time > 0) {
            dx /= time;
            dy /= time;
        } else {
            return;
        }

        dx *= this.speedUpRatio;
        dy *= this.speedUpRatio;
        m.setDx(dx);
        m.setDy(dy);
        this.room.add(m);
    }

    private void onTouchMove(View view, MotionEvent e) {
        this.draw_track = true;
        track.add(new TrackPoint(e.getX(), e.getY(), e.getEventTime()));
        if (track.size() > this.PRESS_QUEUE_LENGTH)
            track.remove(0);

        this.currentCircle.setX(e.getX());
        this.currentCircle.setY(e.getY());
    }

    private boolean onTouchDown(View view, MotionEvent e) {
        this.show_tip = false;
        this.draw_track = false;
        super.onTouchEvent(e);
        track.clear();
        track.add(new TrackPoint(e.getX(), e.getY(), e.getEventTime()));
        int radius = randomRadius();
        int color = randomColor();
        this.currentCircle.setX(e.getX());
        this.currentCircle.setY(e.getY());
        this.currentCircle.setColor(color);
        this.currentCircle.setRadius(radius);
        return true;
    }

    public void pause() {
        room.setRunning(false);
    }

    public void onContinue() {
        room.setRunning(true);
    }

    private static int randomColor() {
        return Color.argb(RANDOM_GEN.nextInt(128) + 128,
                RANDOM_GEN.nextInt(230) + 25, RANDOM_GEN.nextInt(230) + 25,
                RANDOM_GEN.nextInt(230) + 25);
    }

    private int randomRadius() {
        int min = game.getMinRadius();
        int max = game.getMaxRadius();
        return RANDOM_GEN.nextInt(max - min) + min;
    }

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        rectF.top = getTop();
        rectF.left = getLeft();
        rectF.right = getRight();
        rectF.bottom = getBottom();
        if (!room.isAlive())
            room.start();
    }

    public void setGameState(GameState game) {
        this.game = game;
    }
}